<?php
/**
 * @purpose: 观察者接口, 定义观察者具体需要执行的方法，当然方法名和方法个数可以自定义
 * Interface Observer
 */
interface Observer
{
    /**
     * @purpose: 广播通知后，所有已注册的观察者都需要执行该方法。
     * @return mixed
     */
    public function eat();
}

/**
 * @purpse: 定义猫猫类，继承观察者接口，实现具体细节
 * Class Cat
 */
class Cat implements Observer{
    public function eat(){
        echo 'Cat eat fish';
    }
}

/**
 * @purpse: 定义狗狗类，继承观察者接口，实现具体细节
 * Class Dog
 */
class Dog implements Observer{
    public function eat(){
        echo 'Dog eat bones';
    }
}



/**
 * @purpose: 主题接口, 定义添加观察者和广播通知的方法
 * Interface Notify
 */
interface Subject
{
    /**
     * @purpose: 添加观察者
     * @param string $key 给所添加的观察者的一个唯一 key，方便从注册树中移除观察者
     * @param Observer $observer 观察者对象
     * @return mixed
     */
    public function addObserver($key, Observer $observer);

    /**
     * @purpose: 从注册树中移除观察者
     * @param string $key 给所添加的观察者的一个唯一 key，方便从注册树中移除观察者
     * @return mixed
     */
    public function removeObserver($key);

    /**
     * @purpose: 广播通知以注册的观察者
     * @return mixed
     */
    public function notify();
}

/**
 * @purpose: 实现主体接口，主要就是添加观察者和广播通知观察者
 * Class Action
 */
class Action implements Subject
{
    /**
     * @var array 保存所有已注册的观察者
     */
    public $_observer = [];

    /**
     * @purpose: 添加观察者
     * @param string $key 给所添加的观察者的一个唯一 key，方便从注册树中移除观察者
     * @param Observer $observer 观察者对象
     * @return mixed
     */
    public function addObserver($key, Observer $observer)
    {
        $this->_observer[$key] = $observer;
    }

    /**
     * @purpose: 从注册树中移除观察者
     * @param string $key 给所添加的观察者的一个唯一 key，方便从注册树中移除观察者
     * @return mixed
     */
    public function removeObserver($key)
    {
        unset($this->_observer[$key]);
    }

    /**
     * @purpose: 广播通知以注册的观察者，对注册树进行遍历，让每个对象实现其接口提供的操作
     * @return mixed
     */
    public function notify()
    {
        foreach ($this->_observer as $observer) {
            $observer->eat();
        }
    }
}